運用を自動化! CloudWatch と Systems Manager オートメーションでプロセス監視&自動復旧をやってみた

運用を自動化! CloudWatch と Systems Manager オートメーションでプロセス監視&自動復旧をやってみた

Clock Icon2024.10.08

こんにちは。テクニカルサポートチームのShiinaです。

はじめに

CloudWatch で EC2 のプロセス監視を行っていると、アラーム検知時にサービスを再起動させるといった復旧対応の運用を自動化できたらいいなと思いませんか?
今回は CloudWatch アラームの状態変化イベントに基づき、 EventBridge ルールで Systems Manager のオートメーションを実行してサービスを自動復旧させる簡易的な仕組みを実装してみました。
オートメーションを利用して復旧処理を行うため、Lambda 関数の実装は不要です。

概要

CloudWatch エージェントを利用して、プロセス数の閾値をモニタリングする CloudWatch アラームを作成します。
EventBridge ルールを利用して、CloudWatch アラームの状態変化イベント発生時に Systems Manager オートメーションを実行します。
オートメーションでは AWS-RunShellScript を利用し、 systemctl コマンドによるサービス起動で自動復旧を試みます。

前提

  • Systems Manager エージェントがインストールされていること
  • マネージドインスタンスであり、オートメーションの実行が可能であること
  • CloudWatch エージェントがインストールされていること
  • プロセス監視には procstat プラグインの pattern を利用します
  • プロセス復旧には systemctl コマンドを利用します

設定の流れ

はじめに、EventBridge イベントに基づくオートメーションの実行に必要なロールと、オートメーション用のサービスロールの設定を行います。
次に Systems Manager オートメーションドキュメントを作成します。
その後、CloudWatch エージェントとアラームの設定を行なった上で、オートメーションをターゲットとする EventBridge ルールの作成を実施します。

設定手順

1.IAMロール設定

サービスの呼び出しに必要なロールを2つ設定します。
EventBridge イベント用オートメーション実行ロール、 オートメーション用サービスロールを作成します。

EventBridge イベント用オートメーション実行ロール

  • ロール名
    Invoke-Automation-Execution-Role

  • 許可
    下記のインラインポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ActionForSSMAutomation",
            "Action": "ssm:StartAutomationExecution",
            "Effect": "Allow",
            "Resource": [
                "*"
            ]
        }
    ]
}
  • 信頼関係
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "TrustEventBridgeService",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "ssm.amazonaws.com",
                    "events.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Invoke-Automation-Execution-Role-IAM-Global-10-08-2024_11_26_AM
Invoke-Automation-Execution-Role-IAM-Global-10-08-2024_11_26_AM (1)

オートメーション用サービスロール

  • ロール名
    Automation-Execute-Role

  • 許可
    AmazonSSMAutomationRole
    下記のインラインポリシー(arn はご自身のAWSアカウント ID に修正ください)

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "VisualEditor0",
			"Effect": "Allow",
			"Action": "iam:PassRole",
			"Resource": "arn:aws:iam::XXXXXXXXXXX:role/Automation-Execute-Role"
		}
	]
}
  • 信頼関係
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": "ssm.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Automation-Execute-Role-IAM-Global-10-08-2024_11_24_AM
Automation-Execute-Role-IAM-Global-10-08-2024_11_25_AM

2.オートメーションドキュメント作成

Systems Manager ドキュメントよりドキュメントの作成メニューよりオートメーションをクリックします。
2
名前フィールドに ServiceAutoRecoveryAutomation(任意の名前)を入力し、コードタブをクリックします。
下記コードをコピーしてペーストし、ランブックを作成をクリックします。
assumeRole の arn はご自身の環境のオートメーション用サービスロールに修正してください。
3

schemaVersion: '0.3'
description: This book that automatically recovers services triggered by CloudWatch alarm state changes.
parameters:
  pattern:
    type: String
    description: Target Service Name.
  InstanceId:
    type: StringList
    description: Target InstanceId.
assumeRole: arn:aws:iam::XXXXXXXXXXX:role/Automation-Execute-Role
mainSteps:
  - name: CheckAndStartService
    action: aws:runCommand
    isEnd: true
    inputs:
      DocumentName: AWS-RunShellScript
      Parameters:
        commands:
          - '#!/bin/bash'
          - SERVICE_NAME="{{ pattern }}"
          - '# Check the status of the service'
          - if systemctl is-active --quiet "$SERVICE_NAME"; then
          - '  echo "$SERVICE_NAME is already running."'
          - else
          - '  echo "$SERVICE_NAME is stopped. Starting it..."'
          - '  systemctl start "$SERVICE_NAME"'
          - '  # Recheck the status after starting'
          - '  if systemctl is-active --quiet "$SERVICE_NAME"; then'
          - '    echo "Successfully started service $SERVICE_NAME."'
          - '  else'
          - '    echo "Failed to start service $SERVICE_NAME."'
          - '    exit 1'
          - '  fi'
          - fi
      InstanceIds: '{{ InstanceId }}'

3.CloudWatch エージェントの設定

procstat プラグインの pattern でプロセス監視を行う設定を行います。

cd /opt/aws/amazon-cloudwatch-agent/bin/
vi config.json

nginx、sshd、mysqld プロセスを監視する設定ファイル例は次の通りです。

config.json
{
    "agent": {
      "metrics_collection_interval": 60,
      "run_as_user": "cwagent"
    },
    "metrics": {
      "metrics_collected": {
        "procstat": [
          {
            "pattern": "nginx",
            "measurement": [
              "pid_count"
            ],
            "metrics_collection_interval": 60
          },
          {
            "pattern": "sshd",
            "measurement": [
              "pid_count"
            ],
            "metrics_collection_interval": 60
          },
          {
            "pattern": "mysqld",
            "measurement": [
              "pid_count"
            ],
            "metrics_collection_interval": 60
          }
        ]
      },
      "append_dimensions": {
        "InstanceId": "${aws:InstanceId}"
      }
    }
  }

設定ファイルの反映を行います。

sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json

CloudWatch のカスタム名前空間 CWAgent で procstat_lookup_pid_count メトリクスが確認できることを確認します。
1

4.CloudWatch アラームの設定

次のようなアラーム設定を行います

  • メトリクス名:procstat_lookup_pid_count
  • InstanceId:対象 EC2 インスタンス ID
  • pattern:監視プロセス名
  • 統計:最小
  • 期間:1分

プロセスダウンをアラート条件としたいため、プロセス数が 0 以下としたしきい値を設定します。

  • しきい値:procstat_lookup_pid_count <= 0

4

監視したいプロセスごとにアラームを設定します。
今回 nginx、sshd、mysqld プロセスをモニタリングする例として、アラームはそれぞれ次の名前で設定しました。
・WebServerProcessMonitor-nginx
・WebServerProcessMonitor-sshd
・WebServerProcessMonitor-mysqld
アラーム-CloudWatch-ap-northeast-1-10-04-2024_03_14_PM

5.EventBridge ルールの設定

EventBridge ルールの作成を行います。
任意の名前を入力し、ルールタイプではイベントパターンを持つルールを選択します。
ルールを作成-ルールの詳細-Amazon-EventBridge-ap-northeast-1-10-04-2024_03_25_PM
イベントパターンのフィールドに次の値を入力します。
CloudWatch アラーム の arn はご自身の環境のものに修正してください。

{
    "source": ["aws.cloudwatch"],
    "detail-type": ["CloudWatch Alarm State Change"],
    "detail": {
      "state": {
        "value": ["ALARM"]
      }
    },
    "resources": [
      "arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXX:alarm:WebServerProcessMonitor-nginx",
      "arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXX:alarm:WebServerProcessMonitor-sshd",
      "arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXX:alarm:WebServerProcessMonitor-mysqld"
    ]
}

ルールを編集-イベントパターンを構築-Amazon-EventBridge-ap-northeast-1-10-04-2024_03_27_PM

ターゲットタイプでは AWS のサービスを選択します。
Systems Manager オートメーションを選択し、ドキュメントでは作成済みのドキュメント名を選択します。
自動化パラメータ設定では入力トランスフォーマを選択します。

入力パス、テンプレートは次のように設定を行います。

  • 入力パス
{
    "InstanceId": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId",
    "pattern": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.pattern"
}
  • テンプレート
{
    "pattern": ["<pattern>"],
    "InstanceId":["<InstanceId>"]
}

実行ロールは既存のロールにチェックを入れ、作成した EventBridge イベント用オートメーション実行ロール名を選択します。
ルールを編集-ターゲットを選択-Amazon-EventBridge-ap-northeast-1-10-04-2024_03_29_PM

以上で設定は完了です。

やってみた

プロセスを停止して自動復旧の動作検証をやってみます。

監視対象のプロセスをそれぞれ停止してみます。

sudo systemctl stop nginx
sudo systemctl stop sshd
sudo systemctl stop mysqld

サービス停止によりプロセス数がしきい値を下回ります。
しばらくすると CloudWatch アラームがアラート状態に変化します。
アラーム-CloudWatch-ap-northeast-1-10-04-2024_05_47_PM
アラート変化のイベントが発生することで EventBridge ルールによりターゲットであるオートメーションが実行されました。
Automation-Systems-Manager-ap-northeast-1-10-04-2024_05_48_PM
AWS-RunShellScript によりサービス起動の自動復旧処理が行われます。
Execution-detail-Step1-ID-3a0a7cab-029f-4c70-b28b-a29b7fddfa2f-Automation-Systems-Manager-ap-northeast-1-10-08-2024_11_10_AM
自動復旧処理によりサービスが開始されるため、プロセス数がしきい値を上回ります。
しばらくすると CloudWatch アラームが OK 状態に戻ったことが確認できます。
アラーム-CloudWatch-ap-northeast-1-10-04-2024_05_49_PM

デバック方法

EventBridge ルールを設定してみたものの、イベントが発生してもうまくオートメーションが実行されないといったケースがあるかと思います。
デバックに役立つ情報を出力する方法を紹介します。

ターゲットに CloudWatchLogs 設定する

EventBridge ターゲットは複数設定することができます。
CloudWatchLogs をターゲットを設定することで、実際に発生した CloudWatch アラームイベントの JSON を確認することができます。
JSON データと入力トランスフォーマのパスが正しいか確認することができます。
ルールを編集-ターゲットを選択-Amazon-EventBridge-ap-northeast-1-10-07-2024_05_49_PM
CloudWatch-ap-northeast-1-10-07-2024_05_55_PM

デットレターキューを設定する

未処理のイベントを SQS へ送信することができます。
あらかじめ SQS の標準キューを作成の上、デットレターキューを設定します。
何らかの理由で EventBridge ルールでターゲットの呼び出しに失敗した場合、デットレターキューにメッセージが保存されます。
メッセージからエラーコードとエラーメッセージを確認することができます。
ルールを編集-ターゲットを選択-Amazon-EventBridge-ap-northeast-1-10-08-2024_01_24_PM
(参考)メッセージを受信する AWS CLI コマンド例

aws sqs receive-message \
    --queue-url https://sqs.ap-northeast-1.amazonaws.com/XXXXXXXXXXX/XXX \
    --max-number-of-messages 10 \
    --visibility-timeout 30 \
    --wait-time-seconds 0 \
    --attribute-names All \
    --message-attribute-names All \
    --output json
{
    "Messages": [
        {
            "MessageId": "5cd169b7-2e1b-47f0-8c5a-28de9432ff0e",
            "ReceiptHandle": "AQEBSDF0tE7hMvNm+WHeTedJ2IlmeMMywObJ9qudb8cu97Cd78gxVy2SjJ0NdOvLqTfDT7UG2sUtXu2mvskDMP7YeK+FBtQazc0cAlE9sxXcFXpuKms06TzxirjBxlKeNVf5USZSP2biyBOEb88XF2HSCxZ1uSddRuEzYyU7mYjJcRfCk9uJJhwgy6c/3k1AB+ThJ+JAHmr4wTZBj0XG1lU1adnGWnNZWo6VgDYbHMomk/ArAJAhqU5ScAcQruS+i0PXmxaofmSF1X6Cl+hKTOJK0hJOqn92BB3wxT81bvIioZ63EuSGKj+W9zdGLmCrtEZUoV66MS5DDiaAf5MLNLF6HJjwbicNzNCzObqaJHJ2y75g/SRrT3BQiMSnfT+0fKgOIrdZY5Rwc5DgAtwiwZdhMw==",
            "MD5OfBody": "9af3633b723de6ef7ac9c2e3012ad176",
            "Body": "{\n  \"pattern\": [\"nginx\"],\n  \"InstanceId\":[\"i-XXXXXXXXXXX\"]\n}",
            "Attributes": {
                "SenderId": "AIDAIVNDY5GZ7FOG4K4K2",
                "ApproximateFirstReceiveTimestamp": "1728291225293",
                "ApproximateReceiveCount": "4",
                "SentTimestamp": "1728011221747"
            },
            "MD5OfMessageAttributes": "af27f0c1b7cd363a38347b74ff975a3a",
            "MessageAttributes": {
                "ERROR_CODE": {
                    "StringValue": "INVALID_PARAMETER",
                    "DataType": "String"
                },
                "ERROR_MESSAGE": {
                    "StringValue": "The defined assume role is unable to be assumed. (Service: AWSSimpleSystemsManagement; Status Code: 400; Error Code: InvalidAutomationExecutionParametersException; Request ID: 0a022d16-7d89-46dc-9d76-1347484d4909; Proxy: null)",
                    "DataType": "String"
                },
                "RULE_ARN": {
                    "StringValue": "arn:aws:events:ap-northeast-1:XXXXXXXXXXX:rule/nginx-test",
                    "DataType": "String"
                },
                "TARGET_ARN": {
                    "StringValue": "arn:aws:ssm:ap-northeast-1:XXXXXXXXXXX:automation-definition/linux-recovery",
                    "DataType": "String"
                }
            }
        }
    ]
}

まとめ

EventBridge ルールで SystemsManager のオートメーションを実行させてサービスを自動復旧させる方法を紹介しました。
サービスの起動で復旧できるパターンでは障害対応の運用が楽になると思います!
systemctl コマンドでは起動できないようなプロセスは AWS-RunShellScript で起動用のスクリプトをキックして復旧させるといったことも可能です。

本記事が誰かのお役に立てれば幸いです。

参考

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/automation-setup-iam.html
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/running-automations-event-bridge.html
https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-transform-target-input.html
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-procstat-process-metrics.html
https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-rule-dlq.html

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.